﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Media;
using System.Windows.Interop;
using Capture.DirectShow;
using Native_.DirectShow;
using Transport;
namespace Capture
{
    /// <summary>
    /// DirectShowCapturer
    /// </summary>
    public class DirectShowCapturer : FrameCapturer, ICapturer
    {
        private IVideoTransport _encoder;

        public DirectShowCapturer(IVideoTransport encoder)
        {
            if (encoder == null)
                throw new ArgumentNullException("encoder");
            _encoder = encoder;
        }
        public override void Dispose()
        {
            base.Dispose();
            _encoder.Dispose();
        }

        public static bool IsSupported
        {
            get { return (DeviceInfo.GetDevices().Length > 0); }
        }

        public void Initialize()
        {
            //BehaviorVector[(int)CapDevice.BehaviorVectorMask.DispatchOnWorkerThread] = false;
        }

        public void Start()
        {
            Start(() => new DirectShowFrameInfo(this));
        }

        /// <summary>
        /// 
        /// </summary>
        private class DirectShowFrameInfo : FrameInfo
        {
            private IVideoTransport _encoder;

            public DirectShowFrameInfo(DirectShowCapturer parent)
            {
                _encoder = parent._encoder;
            }

            public override void NewFrame(double sampleTime, IntPtr buffer, int bufferLen)
            {
                base.NewFrame(sampleTime, buffer, bufferLen);
                _encoder.EncodeAndTransmit(buffer, bufferLen);
                //Console.Write(".");
                if (_map != IntPtr.Zero)
                {
                    //CopyMemory(_map, buffer, bufferLen);
                    //Console.Write(string.Format(" {0:00}", _grabber.Framerate));
                }
            }

            public override void SetProperties(VideoInfoHeader header)
            {
                base.SetProperties(header);
                //Console.WriteLine("PropertyChangesDone");
                MapToInteropBitmap(Width, Height);
            }

            //[DllImport("Kernel32.dll", EntryPoint = "RtlMoveMemory")]
            //private static extern void CopyMemory(IntPtr Destination, IntPtr Source, int Length);

            #region MapToInteropBitmap

            private IntPtr _map { get; set; }
            private IntPtr _interopBitmapMap;
            private IntPtr _interopBitmapSection;

            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr CreateFileMapping(IntPtr hFile, IntPtr lpFileMappingAttributes, uint flProtect, uint dwMaximumSizeHigh, uint dwMaximumSizeLow, string lpName);
            [DllImport("kernel32.dll", SetLastError = true)]
            private static extern IntPtr MapViewOfFile(IntPtr hFileMappingObject, uint dwDesiredAccess, uint dwFileOffsetHigh, uint dwFileOffsetLow, uint dwNumberOfBytesToMap);

            public InteropBitmap MapToInteropBitmap(int width, int height)
            {
                if ((width != 0) && (height != 0))
                {
                    uint byteSize = (uint)(width * height * PixelFormats.Bgr32.BitsPerPixel / 8);
                    _interopBitmapSection = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, byteSize, null);
                    _interopBitmapMap = MapViewOfFile(_interopBitmapSection, 0xF001F, 0, 0, byteSize);
                    var interopBitmap = (Imaging.CreateBitmapSourceFromMemorySection(_interopBitmapSection, width, height, PixelFormats.Bgr32, width * PixelFormats.Bgr32.BitsPerPixel / 8, 0) as InteropBitmap);
                    _map = _interopBitmapMap;
                    return interopBitmap;
                }
                return null;
            }

            #endregion
        }
    }
}
